// 数据劫持
class Observer {
  constructor (data) {
    this.walk(data)
  }

  walk (data) {
    if (typeof data !== 'object' || data == null) {
      return
    }

    Object.keys(data).forEach(key => {
      this.defineReactive(data, key, data[key])
    })
  }

  defineReactive (obj, key, val) {
    const self = this
    const dep = new Dep()
    Object.defineProperty(obj, key, {
      get () {
        Dep.target && dep.addSub(Dep.target) // 收集依赖
        return val
      },
      set (newVal) {
        if (newVal === val) return
        val = newVal
        self.walk(newValue)
        dep.notify()
      }
    })
  }
}

class Dep {
  constructor () {
    this.subs = []
  }

  addSub (sub) {
    if (sub && sub.update) {
      this.subs.push(sub)
    }
  }

  notify () {
    this.subs.forEach(sub => {
      sub.update()
    })
  }
}

class Watcher {
  constructor (vm, key, cb) {
    this.vm = vm
    // data 中的属性名称
    this.key = key
    // 回调函数负责更新视图
    this.cb = cb

    // 把 watcher 对象记录到 Dep 类的静态属性target
    Dep.target = this
    // 触发 get 方法，在 get 方法中会调用addSub
    this.oldValue = vm[key]
    Dep.target = null // 防止重复添加
  }

  // 当数据发生变化的时候更新视图
  update () {
    let newValue = this.vm[this.key]
    if (this.oldValue === newValue) {
      return
    }

    this.cb(newValue)
  }
}

// 功能
// 当数据变化触发依赖，dep通知所有的 Watcher 实例更新视图
// 自身实例化的时候往dep对象中添加自己
class Watcher {
  constructor (vm, key, cb) {
    this.vm = vm
    // data 中的属性名称
    this.key = key
    // 回调函数负责更新视图
    this.cb = cb

    // 把 watcher 对象记录到 Dep 类的静态属性target
    Dep.target = this
    // 触发 get 方法，在 get 方法中会调用addSub
    this.oldValue = vm[key]
    Dep.target = null // 防止重复添加
  }

  // 当数据发生变化的时候更新视图
  update () {
    let newValue = this.vm[this.key]
    if (this.oldValue === newValue) {
      return
    }

    this.cb(newValue)
  }
}